package com.lxj.easyadapter;

import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.utils.PlainArray;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;

import java.util.List;

/**
 * Created by zhy on 16/4/9.
 */
public class MultiItemTypeAdapter<T> extends BaseItemProvider {

    private static final int BASE_ITEM_TYPE_HEADER = 100000;
    private static final int BASE_ITEM_TYPE_FOOTER = 200000;

    private final PlainArray<Component> mHeaderViews;
    private final PlainArray<Component> mFootViews;
    @NotNull
    private final ItemDelegateManager<T> mItemDelegateManager;
    @Nullable
    private OnItemClickListener mOnItemClickListener = null;
    @NotNull
    private final List<T> data;

    public MultiItemTypeAdapter(@NotNull List<T> data) {
        this.data = data;
        this.mHeaderViews = new PlainArray<>();
        this.mFootViews = new PlainArray<>();
        this.mItemDelegateManager = new ItemDelegateManager<>();
    }

    private int getRealItemCount() {
        return getCount() - getHeadersCount() - getFootersCount();
    }

    public final int getHeadersCount() {
        return mHeaderViews.size();
    }

    public final int getFootersCount() {
        return mFootViews.size();
    }

    @VisibleForTesting
    public final Component getHeaderView(int index) {
        return mHeaderViews.valueAt(index);
    }

    @VisibleForTesting
    public final Component getFooterView(int index) {
        return mFootViews.valueAt(index);
    }

    @Override
    public int getItemComponentType(int position) {
        if (isHeaderViewPos(position)) {
            return mHeaderViews.keyAt(position);
        } else if (isFooterViewPos(position)) {
            return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
        } else {
            return !useItemDelegateManager() ? super.getItemComponentType(position)
                    : mItemDelegateManager.getItemViewType(data.get(position - getHeadersCount()), position - getHeadersCount());
        }
    }

    @NotNull
    public ViewHolder onCreateViewHolder(@NotNull ComponentContainer parent, int viewType) {
        if (mHeaderViews.get(viewType).orElse(null) != null) {
            return ViewHolder.createViewHolder(mHeaderViews.get(viewType).get());
        } else if (mFootViews.get(viewType).orElse(null) != null) {
            return ViewHolder.createViewHolder(mFootViews.get(viewType).get());
        } else {
            ItemDelegate<T> itemViewDelegate = mItemDelegateManager.getItemViewDelegate(viewType);
            int layoutId = itemViewDelegate.getLayoutId();
            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), parent, layoutId);
            this.onViewHolderCreated(holder, holder.getConvertView());
            this.setListener(parent, holder, viewType);
            return holder;
        }
    }

    public final void onViewHolderCreated(@NotNull ViewHolder holder, @NotNull Component itemView) {
    }

    public final void convert(@NotNull ViewHolder holder, T t) {
        mItemDelegateManager.convert(holder, t, holder.getAdapterPosition() - this.getHeadersCount());
    }

    protected final boolean isEnabled(int viewType) {
        return true;
    }

    protected final void setListener(@NotNull ComponentContainer parent, @NotNull final ViewHolder viewHolder, int viewType) {
        if (isEnabled(viewType)) {
            viewHolder.getConvertView().setClickedListener(new Component.ClickedListener() {
                public final void onClick(Component v) {
                    if (mOnItemClickListener != null) {
                        int position = viewHolder.getAdapterPosition() - getHeadersCount();
                        mOnItemClickListener.onItemClick(v, viewHolder, position);
                    }

                }
            });
            viewHolder.getConvertView().setLongClickedListener(new Component.LongClickedListener() {
                @Override
                public void onLongClicked(Component v) {
                    if (mOnItemClickListener != null) {
                        int position = viewHolder.getAdapterPosition() - getHeadersCount();
                        mOnItemClickListener.onItemLongClick(v, viewHolder, position);
                    }
                }
            });
        }
    }

    public void onBindViewHolder(@NotNull ViewHolder holder, int position) {
        if (!isHeaderViewPos(position)) {
            if (!isFooterViewPos(position)) {
                convert(holder, data.get(position - getHeadersCount()));
            }
        }
    }

    @Override
    public int getCount() {
        int itemCount = data.size();
        return getHeadersCount() + getFootersCount() + itemCount;
    }

    private boolean isHeaderViewPos(int position) {
        return position < this.getHeadersCount();
    }

    private boolean isFooterViewPos(int position) {
        return position >= this.getHeadersCount() + this.getRealItemCount();
    }

    public final void addHeaderView(@NotNull Component view) {
        this.mHeaderViews.put(this.mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
    }

    public final void addFootView(@NotNull Component view) {
        this.mFootViews.put(this.mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
    }

    @NotNull
    public final MultiItemTypeAdapter<T> addItemDelegate(@NotNull ItemDelegate<T> itemViewDelegate) {
        this.mItemDelegateManager.addDelegate(itemViewDelegate);
        return this;
    }

    @NotNull
    public final MultiItemTypeAdapter<T> addItemDelegate(int viewType, @NotNull ItemDelegate<T> itemViewDelegate) {
        this.mItemDelegateManager.addDelegate(viewType, itemViewDelegate);
        return this;
    }

    protected final boolean useItemDelegateManager() {
        return this.mItemDelegateManager.getItemViewDelegateCount() > 0;
    }

    public final void setOnItemClickListener(@NotNull MultiItemTypeAdapter.OnItemClickListener onItemClickListener) {
        this.mOnItemClickListener = onItemClickListener;
    }

    public interface OnItemClickListener {
        void onItemClick(@NotNull Component view, @NotNull ViewHolder holder, int position);

        boolean onItemLongClick(@NotNull Component view, @NotNull ViewHolder holder, int position);
    }

    public static class SimpleOnItemClickListener implements OnItemClickListener {
        public void onItemClick(@NotNull Component view, @NotNull ViewHolder holder, int position) {
        }

        public boolean onItemLongClick(@NotNull Component view, @NotNull ViewHolder holder, int position) {
            return false;
        }
    }

    @Override
    public Object getItem(int i) {
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
        ViewHolder holder = onCreateViewHolder(componentContainer, getItemComponentType(i));
        holder.setAdapterPosition(i);
        onBindViewHolder(holder, i);
        return holder.getConvertView();
    }
}
